package translate;

import Base.ResourceTest;
import EntityBuilder.RenterBuilder;
import com.huawei.translate.api.TranslateApi;
import com.huawei.translate.model.Renter;
import com.huawei.translate.provider.*;
import com.huawei.translate.service.TranslateRecordService;
import com.huawei.translate.vo.*;
import com.huawei.translate.vo.translate.TranslateRequest;
import com.huawei.translate.vo.translate.TranslateResponse;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.UUID;

import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.*;

@RunWith(SpringRunner.class)
public class When_user_request_translate extends ResourceTest {

    @Autowired
    @Mock
    private TranslateProviderFactory translateProviderFactory;

    @Autowired
    @Mock
    private MSTranslateProvider msTranslateProvider;

    @Autowired
    @Mock
    private TranslateRecordService translateRecordService;

    @Autowired
    @InjectMocks
    private TranslateApi translateApi;

    private Renter renter;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void should_log_when_request_translate() {

        renter = new RenterBuilder(renterRepository).WithAppSecret(UUID.randomUUID().toString()).Build();
        ResponseEntity<AccessTokenResponse> accessTokenResponse = generateAccessToken();
        TranslateResponse translateResponse = new TranslateResponse(HttpStatus.OK.value(), "HelloWorld");

        TranslateRequest request = new TranslateRequest(accessTokenResponse.getBody().getAccessToken(), "zh", "ar", translateResponse.getMessage());

        TranslateProvider provider = new MSTranslateProvider();
        TranslateProvider spy = spy(provider);
        doReturn(translateResponse).when(spy).translate(isA(TranslateRequest.class));
        doReturn(TranslateProviderType.MS.getDescription()).when(spy).toDescription();
        when(translateProviderFactory.getProvider(isA(TranslateRequest.class))).thenReturn(spy);

        sendTranslateRequestWithHeader(request, "Hello").getBody();

        Mockito.verify(translateRecordService).record(isA(TranslateRequest.class), isA(TranslateResponse.class),
                anyString(), anyString());
    }



    @Test
    public void should_retry_ms_when_hw_or_you_dao_not_available() {

        renter = new RenterBuilder(renterRepository).WithAppSecret(UUID.randomUUID().toString()).Build();
        ResponseEntity<AccessTokenResponse> accessTokenResponse = generateAccessToken();
        TranslateResponse translateResponse = new TranslateResponse(HttpStatus.OK.value(), "HelloWorld");

        TranslateRequest request = new TranslateRequest(accessTokenResponse.getBody().getAccessToken(), "zh", "en", translateResponse.getMessage());
        TranslateProvider provider = new HuaWeiTranslateProvider();
        TranslateProvider spy = spy(provider);
        doReturn(null).when(spy).translate(isA(TranslateRequest.class));
        when(translateProviderFactory.getProvider(isA(TranslateRequest.class))).thenReturn(spy);
        when(msTranslateProvider.translate(isA(TranslateRequest.class))).thenReturn(translateResponse);

        Assert.assertEquals(HttpStatus.OK, accessTokenResponse.getStatusCode());

        ResponseEntity<TranslateResponse> response = sendTranslateRequest(request);

        Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
        Assert.assertEquals("HelloWorld", response.getBody().getMessage());
        Assert.assertEquals(HttpStatus.OK.value(), response.getBody().getCode());
    }

    @Test
    public void should_return_translated_text_when_request_valid() throws Exception {

        renter = new RenterBuilder(renterRepository).WithAppSecret(UUID.randomUUID().toString()).Build();

        TranslateResponse translateResponse = new TranslateResponse(HttpStatus.OK.value(), "HelloWorld");

        MSTranslateProvider provider = new MSTranslateProvider();
        MSTranslateProvider spy = spy(provider);
        doReturn(translateResponse).when(spy).translate(isA(TranslateRequest.class));
        when(translateProviderFactory.getProvider(isA(TranslateRequest.class))).thenReturn(spy);

        ResponseEntity<AccessTokenResponse> accessTokenResponse = generateAccessToken();
        TranslateRequest request = new TranslateRequest(accessTokenResponse.getBody().getAccessToken(), "en", "en", translateResponse.getMessage());

        Assert.assertEquals(HttpStatus.OK, accessTokenResponse.getStatusCode());

        ResponseEntity<TranslateResponse> response = sendTranslateRequest(request);

        Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
        Assert.assertEquals(translateResponse.getMessage(), response.getBody().getMessage());
        Assert.assertEquals(HttpStatus.OK.value(), response.getBody().getCode());
    }

    @Test
    public void should_return_forbidden_when_accesstoken_invalid() {
        String accessToken = "invalid token";
        TranslateRequest request = new TranslateRequest(accessToken, "en", "zh", "HelloWorld");

        ResponseEntity<TranslateResponse> responseEntity = sendTranslateRequest(request);

        Assert.assertEquals(HttpStatus.FORBIDDEN, responseEntity.getStatusCode());
        Assert.assertEquals(HttpStatus.FORBIDDEN.value(), responseEntity.getBody().getCode());
    }

    @Test
    public void should_return_forbidden_when_user_not_exist() {

        String accessToken = "ZGRiZjE5NTAtMGQwOC0xMWU3LTkzYWUtOTIzNjFmMDAyNjcxMTQ4OTk3MTgwOA==";
        TranslateRequest request = new TranslateRequest(accessToken, "en", "zh", "HelloWorld");

        ResponseEntity<TranslateResponse> responseEntity = sendTranslateRequest(request);

        Assert.assertEquals(HttpStatus.FORBIDDEN, responseEntity.getStatusCode());
        Assert.assertEquals(HttpStatus.FORBIDDEN.value(), responseEntity.getBody().getCode());
    }

    @Test
    public void should_return_bad_request_when_request_not_valid() {
        TranslateRequest request = new TranslateRequest("", "", "", "");

        ResponseEntity<TranslateResponse> responseEntity = sendTranslateRequest(request);

        Assert.assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode());
        Assert.assertEquals(HttpStatus.BAD_REQUEST.value(), responseEntity.getBody().getCode());
    }

    // TODO: 28/03/2017 need mock static method ,power mock combine junit does not work(diangui)
//    @Test
//    public void should_return_forbidden_when_accesstoken_expired(){
//
//        String accessToken = generateAccessToken(renter.getAppKey());
//
//        TranslateRequest request = new TranslateRequest(accessToken,"en","zh","HelloWorld");
//
//        ResponseEntity<TranslateResponse> responseEntity = sendTranslateRequest(request);
//
//        Assert.assertEquals(HttpStatus.FORBIDDEN,responseEntity.getStatusCode());
//    }

    private ResponseEntity<TranslateResponse> sendTranslateRequest(TranslateRequest request) {
        return this.testRestTemplate.postForEntity("/api/translates", request, TranslateResponse.class);
    }

    private ResponseEntity<TranslateResponse> sendTranslateRequestWithHeader(TranslateRequest request, String traceId) {
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.add("traceid", traceId);
        HttpEntity httpEntity = new HttpEntity(request, requestHeaders);
        return this.testRestTemplate.exchange("/api/translates", HttpMethod.POST, httpEntity, TranslateResponse.class);
    }

    private ResponseEntity<AccessTokenResponse> sendGenerateAccessTokenRequest(AccessTokenGenerateRequest request) {
        return this.testRestTemplate.postForEntity("/api/oauth/generate", request, AccessTokenResponse.class);
    }

    private ResponseEntity<AccessTokenResponse> generateAccessToken() {
        return sendGenerateAccessTokenRequest(new AccessTokenGenerateRequest(renter.getAppSecret(), "Secret"));
    }
}
